//
//  TYZBaseWebViewController.m
//  DriveSchoolCoach
//
//  Created by TangBin on 2019/7/4.
//  Copyright © 2019 TangBin. All rights reserved.
//

#import "TYZBaseWebViewController.h"
#import "AppDelegate.h"

/*
 WKScriptMessageHandler 这个协议类专门用来处理监听javascript方法从而调用原生OC方法，和WKUserContentControlle搭配使用
 
 WKNavigationDelegate 主要处理一些跳转、加载处理操作
 
 WKUIDelegate 主要处理JS脚本，确认框，警告框等
 
 JS调用OC
 这个实现主要是依靠WKScriptMessageHandler协议类和WKUserContentController两个类：WKUserContentController对象负责注册JS方法，设置处理接收JS方法的代理，代理遵守WKScriptMessageHandler，实现捕捉到JS消息的回调方法，详情可以看第一步中对这两个类的介绍。
 //这个类主要用来做native与JavaScript的交互管理
 WKUserContentController * wkUController = [[WKUserContentController alloc] init];
 //注册一个name为jsToOcNoPrams的js方法，设置处理接收JS方法的代理
 [wkUController addScriptMessageHandler:self  name:@"jsToOcNoPrams"];
 [wkUController addScriptMessageHandler:self  name:@"jsToOcWithPrams"];
 config.userContentController = wkUController;
 
 注意：遵守WKScriptMessageHandler协议，代理是由WKUserContentControl设置
 //通过接收JS传出消息的name进行捕捉的回调方法  js调OC
 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
 NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
 }
 
 
 OC调用JS
 //OC调用JS  changeColor()是JS方法名，completionHandler是异步回调block
 NSString *jsString = [NSString stringWithFormat:@"changeColor('%@')", @"Js参数"];
 [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {
 NSLog(@"改变HTML的背景色");
 }];
 
 //改变字体大小 调用原生JS方法
 NSString *jsFont = [NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'", arc4random()%99 + 100];
 [_webView evaluateJavaScript:jsFont completionHandler:nil];
 
 
 https://www.cnblogs.com/oc-bowen/p/5946383.html
 
 */

@interface TYZBaseWebViewController ()

//@property (nonatomic, strong) NSURL *url;

@property (nonatomic, strong) WKWebView  *webView;

@property (nonatomic, strong) UIProgressView *progress;

@property (nonatomic, assign) BOOL isForceOrientation;


- (void)initWithWebView;
@end

@implementation TYZBaseWebViewController


- (void)dealloc
{
    debugMethod();
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
    [self.webView removeObserver:self forKeyPath:@"title"];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIWindowDidBecomeVisibleNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIWindowDidBecomeHiddenNotification object:nil];
    
    if (self.isAllowNative)
    {
        [self.webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
    }
}

/**
 初始化
 
 @param url url
 @param isForceOrientation 是否可以旋转（这里是在有视频播放的时候，可能视频需要全屏）
 @return return value description
 */
- (instancetype)initWithUrl:(NSURL *)url isForceOrientation:(BOOL)isForceOrientation
{
    self.url = url;
    self.isForceOrientation = isForceOrientation;
    return [self init];
}

- (void)initWithVar
{
    [super initWithVar];
    
}

- (void)initWithNavBar
{
    [super initWithNavBar];
    
    self.navigationItem.title = self.customTitle;
    
    CGRect frame = CGRectMake(0, 0, 30, 44);
    UIButton *btnBack = [UIButton buttonWithType:UIButtonTypeCustom];
    btnBack.frame = frame;
    [btnBack addTarget:self action:@selector(clickedBack:) forControlEvents:UIControlEventTouchUpInside];
    [btnBack setImage:kNavBtnBackImage forState:UIControlStateNormal];
    UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:btnBack];
    
    UIButton *btnClose = [UIButton buttonWithType:UIButtonTypeCustom];
    btnClose.frame = frame;
    [btnClose addTarget:self action:@selector(actionClose:) forControlEvents:UIControlEventTouchUpInside];
    [btnClose setImage:kNavBtnWebcloseImage forState:UIControlStateNormal];
    UIBarButtonItem *closeItem = [[UIBarButtonItem alloc] initWithCustomView:btnClose];
    
    self.navigationItem.leftBarButtonItems = @[backItem, closeItem];
}

- (void)initWithSubView
{
    [super initWithSubView];
    
    [self initWithScrollView];
    
    [self initWithWebView];
    
    
    //TODO:kvo监听，获得页面title和加载进度值
    [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
    
    
    if (self.isForceOrientation)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterFullScreen:) name:UIWindowDidBecomeVisibleNotification  object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willExitFullScreen:) name:UIWindowDidBecomeHiddenNotification object:nil];
    }
    
    if (self.isAllowNative)
    {
        [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL];
    }
}

- (void)initWithWebView
{
    if (!_webView)
    {
        CGSize size = [UIScreen mainScreen].bounds.size;
        CGRect frame = CGRectMake(0, 0, size.width, size.height - NAVBAR_HEIGHT_STATUS);
        WKWebViewConfiguration *config = [WKWebViewConfiguration new];
        config.userContentController = [ self wkwebViewScalPreferences];
        //初始化偏好设置属性：preferences
        config.preferences = [WKPreferences new];
        //The minimum font size in points default is 0;
        config.preferences.minimumFontSize = 10;
        //是否支持JavaScript
        config.preferences.javaScriptEnabled = YES;
        //不通过用户交互，是否可以打开窗口
        //        config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
        
        _webView = [[WKWebView alloc]initWithFrame:frame configuration:config];
        
        // 这行代码可以是侧滑返回webView的上一级，而不是根控制器（*只针对侧滑有效）
        [_webView setAllowsBackForwardNavigationGestures:true];
        _webView.UIDelegate = self; // UI 代理
//        _webView.scrollView.scrollEnabled = YES;
        _webView.navigationDelegate = self; // 导航代理
        
        if (self.isAllowNative)
        {
            _webView.scrollView.scrollEnabled = NO;
            [self.bgScrollView addSubview:_webView];
        }
        else
        {
            _webView.scrollView.scrollEnabled = YES;
            [self.view addSubview:_webView];
        }
    }
    // http://111.39.245.157:8087/mobile/question.html
//    NSURL *url = [NSURL URLWithString:_urlStr];
//    debugLog(@"url=%@", _url);
    if (_url && ![_url isEqual:[NSNull null]] && _url.absoluteString && ![objectNull(_url.absoluteString) isEqualToString:@""])
    {
//        [self.webView loadRequest:[NSURLRequest requestWithURL:_url]];
        [self loadWebView];
    }
}

- (void)initWithScrollView
{
    if (!self.isAllowNative)
    {
        return;
    }
    
    CGRect frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight - NAVBAR_HEIGHT_STATUS);
    _bgScrollView = [[UIScrollView alloc] initWithFrame:frame];
    _bgScrollView.backgroundColor = [UIColor colorWithHexString:@"#f5f5f5"];
    [self.view addSubview:_bgScrollView];
}


- (UIProgressView *)progress
{
    if (!_progress)
    {
        
        _progress = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 5)];
//        _progress.progressTintColor = ThemeColor; // #309cf5
//        _progress.trackTintColor = TableColor; // f9f9f9
        [self.view addSubview:_progress];
    }
    return _progress;
}

- (void)loadWebView
{
    if (_url)
    {
        if ([_url.absoluteString hasPrefix:@"http"])
        {
            [self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
        }
        else
        {
            if (@available(iOS 9.0, *))
            {
                [self.webView loadFileURL:_url allowingReadAccessToURL:_url];
            }
            else
            {
                [self.webView loadRequest:[NSURLRequest requestWithURL:self.url]];
            }
        }
    }
}

- (void)loadWebView:(NSURL *)url
{
    if (url)
    {
        self.url = url;
    }
    [self loadWebView];
}


- (void)actionClose:(id)sender
{
    if (self.isBack)
    {
        [self.navigationController popViewControllerAnimated:YES];
    }
    else
    {
        [super clickedBack:sender];
    }
}

#pragma mark KVO的监听代理
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    //加载进度值
    if ([keyPath isEqualToString:@"estimatedProgress"])
    {
        if (object == self.webView)
        {
            [self.progress setAlpha:1.0f];
            [self.progress setProgress:self.webView.estimatedProgress animated:YES];
            if(self.webView.estimatedProgress >= 1.0f)
            {
                [UIView animateWithDuration:0.5f delay:0.3f options:UIViewAnimationOptionCurveEaseOut  animations:^{
                    [self.progress setAlpha:0.0f];
                    
                } completion:^(BOOL finished) {
                    [self.progress setProgress:0.0f animated:NO];
                    
                }];
            }
        }
        else
        {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    //网页title
    else if ([keyPath isEqualToString:@"title"])
    {
        if (object == self.webView)
        {
            if (!self.isCustomTitle && ![objectNull(self.webView.title) isEqualToString:@""])
            {
                self.navigationItem.title = self.webView.title;
            }
        }
        else
        {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    else if ([keyPath isEqualToString:@"contentSize"])
    {
        NSValue* value = change[@"new"];
        CGSize size = [value CGSizeValue];
        CGFloat height = size.height;
        CGRect webFrame = _webView.frame;
        webFrame.size.height = height;
        _webView.frame = webFrame;
        self.bgScrollView.contentSize = CGSizeMake(0, height + self.baseTopView.height);
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)willEnterFullScreen:(NSNotification *)noti
{
    AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
    appDel.isForcePortrait = NO;
    appDel.isForceLandscape = YES;
    [appDel application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
    
    TYZBaseNavigationController *nav = (TYZBaseNavigationController *)self.navigationController;
    nav.interfaceOrientation = UIInterfaceOrientationLandscapeRight;
    nav.interfaceOrientationMask = UIInterfaceOrientationMaskLandscapeRight;
    
    [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeRight) forKey:@"orientation"];
    
    // 刷新
    [UIViewController attemptRotationToDeviceOrientation];
}

- (void)willExitFullScreen:(NSNotification *)noti
{
    [UIApplication sharedApplication].statusBarHidden = YES;
    AppDelegate *appDel = (AppDelegate *)[UIApplication sharedApplication].delegate;
    appDel.isForcePortrait = YES;
    appDel.isForceLandscape = NO;
    [appDel application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:self.view.window];
    
    TYZBaseNavigationController *nav = (TYZBaseNavigationController *)self.navigationController;
    nav.interfaceOrientation = UIInterfaceOrientationPortrait;
    nav.interfaceOrientationMask = UIInterfaceOrientationMaskPortrait;
    
    [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"];
    
    // 刷新
    [UIViewController attemptRotationToDeviceOrientation];
}


#pragma mark - 大小适应
- (WKUserContentController *)wkwebViewScalPreferences
{
    NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
    WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
    WKUserContentController *wkUController = [[WKUserContentController alloc] init];
    [wkUController addUserScript:wkUScript];
    
    return wkUController;
}

- (void)clickedBack:(id)sender
{
    if (self.isBack)
    {
        [self.navigationController popViewControllerAnimated:YES];
        return;
    }
    if ([self.webView canGoBack]  && !self.isDirectlyClosed)
    {
        //如果有则返回
        [self.webView goBack];
    }
    else
    {
        [super clickedBack:sender];
    }
}


#pragma mark - WKUIDelegate 主要处理JS脚本，确认框，警告框等。因此WKNavigationDelegate更加常用。

// web界面中警告框时调用
/*- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
 {
 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"HTML的弹出框" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
 [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 completionHandler();
 }])];
 [self presentViewController:alertController animated:YES completion:nil];
 }*/

// 确认框
// javascript调用confirm方法后，回调的方法 confirm是js中的确定框，需要在block中把用户选择的情况传递进去
/*- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
 {
 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
 [alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
 completionHandler(NO);
 }])];
 [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 completionHandler(YES);
 }])];
 [self presentViewController:alertController animated:YES completion:nil];
 }*/

// 输入框
// javascript调用prompt方法后，回调的方法，prompt是js中的输入框，需要在block中把用户输入的信息输入
/*- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler
 {
 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
 [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
 textField.text = defaultText;
 }];
 [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
 completionHandler(alertController.textFields[0].text?:@"");
 }])];
 [self presentViewController:alertController animated:YES completion:nil];
 }*/

// 页面时弹出窗口 _blank处理
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
    if (!navigationAction.targetFrame.isMainFrame) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

#pragma mark - WKNavigationDelegate 主要处理一些跳转、加载处理操作

// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation
{
    self.progress.hidden = NO;
    [self.view bringSubviewToFront:self.progress];
}

// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation
{
    
}

// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
    if (!self.isCustomTitle)
    {
        if (![objectNull(self.webView.title) isEqualToString:@""])
        {
            self.navigationItem.title = webView.title;
        }
        
        __weak typeof(self)weakSelf = self;
        [self.webView evaluateJavaScript:@"document.title" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
            NSString *title = response;
            if (![objectNull(title) isEqualToString:@""])
            {
                weakSelf.navigationItem.title = title;
            }
        }];
    }
    /*
     NSString *jsStr = @"var arr = ['tang','bin'];";
     [self.wkwebView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
     NSLog(@"%@----%@", result, [error localizedDescription]);
     }];
     */
}

- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
    self.progress.hidden = YES;
}

// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(nonnull NSError *)error
{
    
}

// 在收到响应后，决定是否跳转
/*- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(nonnull WKNavigationResponse *)navigationResponse decisionHandler:(nonnull void (^)(WKNavigationResponsePolicy))decisionHandler
 {
 NSLog(@"absolutestring=%@", navigationResponse.response.URL.absoluteString);
 
 // 允许跳转
 //    decisionHandler(WKNavigationResponsePolicyAllow);
 
 // 不允许跳转
 //    decisionHandler(WKNavigationResponsePolicyCancel);
 
 }
 */
// 在发送请求之前，决定是否跳转
/*- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler
 {
 NSLog(@"absolutestring=%@", navigationAction.request.URL.absoluteString);
 
 // 允许跳转
 //    decisionHandler(WKNavigationActionPolicyAllow);
 
 // 不信息跳转
 //    decisionHandler(WKNavigationActionPolicyCancel);
 }*/

#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    if (message.name)
    {
        NSLog(@"OC 层面的消息");
    }
    NSLog(@"message == %@ --- %@", message.name, message.body);
}

@end
